#pragma once
#include <pugixml.hpp>
#include <loguru.hpp>
#include <json/json.h>
#include <random>

#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
#define make_dir(path) _mkdir(path.c_str())
#define STAT_STRUCT _stat
#define STAT_FUNC _stat
#else
#include <unistd.h>
#include <iostream>

#define STAT_STRUCT stat
#define STAT_FUNC stat
#define make_dir(path) mkdir(path.c_str(), 0755)
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif

namespace Util
{
    class MiscUtil
    {
    public:
        /// @brief 获取指定长度的随机字符串
        /// @param len
        /// @return 生成的随机字符串
        static std::string getRandomString(std::size_t len)
        {
            /*
            note: cpp生成指定长度的随机字符串
             */
            std::string chars = "abcdefghijklmnopqrstuvwxyz"
                                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                "0123456789";
            std::random_device rd;        // 用于种子
            std::mt19937 generator(rd()); // 生成器
            std::uniform_int_distribution<> distribution(0, chars.size() - 1);

            std::string randomStr;
            for (size_t i; i < len; ++i)
            {
                randomStr += chars[distribution(generator)];
            }
            return randomStr;
        };

        /// @brief 获取当前UNIX时间戳(精确到秒)
        static long long getCurrentTimeMillis()
        {
            auto now = std::chrono::system_clock::now();
            auto duration = now.time_since_epoch();
            auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
            return milliseconds.count();
        }

        /// @brief 将时间戳格式化为 YY-MM-DD hh-mm-SS 格式
        /// @param timestamp 时间戳
        /// @return
        static std::string formatTimestamp(long timestamp)
        {
            // 创建时间结构体
            struct tm *time_info;
            char buffer[20]; // 存储格式化后的字符串

            // 时间戳转换为本地时间
            time_t raw_time = static_cast<time_t>(timestamp);
            time_info = localtime(&raw_time);

            // 格式化时间为 YY-MM-DD hh-mm-SS 格式
            strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_info);

            // 返回string
            return std::string(buffer);
        }

        /// @brief 通过当前时间戳获取pcap文件名
        /// @param isFullPath
        /// @return
        static std::string getPcapNameByCurrentTimestamp(bool isFullPath = true)
        {
            // 读取当前时间
            std::time_t now = std::time(nullptr);
            std::tm *localTime = std::localtime(&now);

            // 格式化文件名
            char buffer[64];
            std::strftime(buffer, sizeof(buffer), "easytshark_%Y-%m-%d_%H-%M-%S.pcap", localTime);
            return isFullPath ? getDefaultDataDir() + std::string(buffer) : std::string(buffer);
        }

        

        /// @brief 将pcap转换的xml文件转换为json
        /// @param xmlContent
        /// @param outJsonValue
        /// @return 转换成功返回true,失败返回false
        static bool xml2Json(const std::string &xmlContent, Json::Value &outJsonValue)
        {
            pugi::xml_document doc;
            doc.load_string(xmlContent.c_str());
            if (!doc)
            {
                LOG_F(ERROR, "pugixml load string failed: %s", xmlContent.c_str());
                return false;
            }
            outJsonValue = xml2JsonRecurse(doc);
            return true;
        }

        static std::string getDefaultDataDir()
        {
            static std::string dir = "";
            if (!dir.empty())
            {
                return dir;
            }
#ifdef _WIN32
            dir = std::string(std::getenv("APPDATA")) + "\\easytshark\\";
#else
            dir = std::string(std::getenv("HOME")) + "/easytshark/";
#endif
            createDirectory(dir);
            return dir;
        }

        static bool fileExists(const std::string &path)
        {
            struct stat info;
            return stat(path.c_str(), &info) == 0;
        }

        static bool directoryExists(const std::string &path)
        {
            struct stat info;
            return (stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR));
        }

        static bool createDirectory(const std::string &path)
        {
            if (directoryExists(path))
            {
                return true;
            }
            size_t pos = path.find_last_of("/\\");
            if (pos != std::string::npos)
            {
                std::string parentDir = path.substr(0, pos);
                if (!createDirectory(parentDir))
                {
                    return false;
                }
            }
            if (make_dir(path) == 0)
            {
                return true;
            }
            else
            {
                perror("Error creating directory");
                return false;
            }
        }

    private:
        /// @brief 将xml_node转换为json
        /// @param node
        /// @return 转换后的json节点
        static Json::Value xml2JsonRecurse(pugi::xml_node &node)
        {
            Json::Value value;
            // 设置属性
            for (auto it = node.attributes_begin(); it != node.attributes_end(); ++it)
            {
                value[it->name()] = it->value();
            }
            // 添加子标签
            Json::Value packets, protos, fields;
            for (auto &child : node.children())
            {
                std::string name = child.name();
                if (strcmp(child.name(), "packet") == 0)
                {
                    packets.append(xml2JsonRecurse(child));
                }
                else if (strcmp(child.name(), "proto") == 0)
                {
                    protos.append(xml2JsonRecurse(child));
                }
                else if (strcmp(child.name(), "field") == 0)
                {
                    fields.append(xml2JsonRecurse(child));
                }
                else
                {
                    value[child.name()] = xml2JsonRecurse(child);
                }
            }
            if (!packets.empty())
            {
                value["packet"] = packets;
            }
            if (!protos.empty())
            {
                value["proto"] = protos;
            }
            if (!fields.empty())
            {
                value["field"] = fields;
            }
            return value;
        }
    };

}